package com.utils;

import cn.hutool.core.date.DateUtil;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Component
public class JWTUtils {

    public static final long JWT_WEB_TTL = 20 * 365 * 24 * 60 * 60 * 1000L;//设定token过期时间20年
    private static final String JWT_SECRET = "qwersdafzgkogtnm";// JWT密匙
    private static final SecretKey JWT_KEY;// 使用JWT密匙生成的加密key
    //存放鉴权信息的Header名称，默认是Authorization
    public static final String JWT_TOKEN = "token";
    static Logger log = LoggerFactory.getLogger(JWTUtils.class);
    static {
        byte[] encodedKey = Base64.decodeBase64(JWT_SECRET);
        JWT_KEY = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
    }

    /**
     * 创建JWT令牌，签发时间为当前时间
     *
     * @return
     */
    public static String getToken(Map claims) {
        // 生成JWT的时间，即签发时间
        long nowMillis = System.currentTimeMillis();
        //把他写死不是好办法，他应该是活的，
        // 我想声明啥我就往里添加啥map就行
//        Map claims = new HashMap<>();
//        claims.put("userName", userName);
//        claims.put("password", password);

        //setId：是JWT的唯一标识，根据业务需要，这个可以设置为一个不重复的值，主要用来作为一次性token,从而回避重放攻击。
//        String mytoken=Jwts.builder().setClaims(claims)
//                .setId(UUID.randomUUID().toString().replace("-", ""))
//                //签发时间
//                .setIssuedAt(new Date(nowMillis))
//                //算法和密钥是什么
//                .signWith(SignatureAlgorithm.HS256, JWT_KEY)
//                //过期时间
//                .setExpiration(new Date(nowMillis + JWT_WEB_TTL))
//                .compact();
//        log.info(mytoken);
        return Jwts.builder().setClaims(claims)
                .setId(UUID.randomUUID().toString().replace("-", ""))
                //签发时间
                .setIssuedAt(new Date(nowMillis))
                //算法和密钥是什么
                .signWith(SignatureAlgorithm.HS256, JWT_KEY)
                //过期时间
                .setExpiration(new Date(nowMillis + JWT_WEB_TTL))
                .compact();
    }


    /**
     * 生成token
     *
     * @return
     */
//    public static String getToken(String userId, String password) {
//        return JWT.create().withAudience(userId) // 将 user id 保存到 token 里面,作为载荷
//                .withExpiresAt(DateUtil.offsetHour(new Date(), 2)) // 2小时后token过期
//                .sign(Algorithm.HMAC256(password)); // 以 password 作为 token 的密钥
//    }

    //key是什么？是claims声明的值
    public static String getTokenValueByKey(String token,String key){
        //获取token

        Claims claims = validateJwtToken(token);
        if (null == claims) {
            //token令牌已过期或已失效
            return null;
        }
        return claims.get(key) == null?null:claims.get(key).toString();
    }
    /**
     * 验证jwt令牌，验证通过返回声明(包括公有和私有)，返回null则表示验证失败
     */
    public static Claims validateJwtToken(String jwt) {
        Claims claims = null;
        try {
            if (null != jwt) {
                claims = parseToken(jwt);
            }
        }catch (ExpiredJwtException e){
            log.error("jwt{}过期",jwt);
            MyJwtParser mjp = new MyJwtParser();
            claims = mjp.getClaims(jwt);
        }catch (Exception e) {
            log.error("jwt{}校验失败",jwt);
        }
        return claims;
    }
    /**
     * 解密jwt，获得所有声明(包括标准和私有声明)
     *
     * @param token
     * @return
     * @throws Exception
     */
    public static Claims parseToken(String token) {
        Claims claims = Jwts.parser().setSigningKey("").parseClaimsJws(token).getBody();
        return claims;
    }

}
